package gin

import (
	authpb "e-commerce/services/auth-service/api/pb"
	orderpb "e-commerce/services/order-service/api/pb"
	"e-commerce/services/order-service/internal/service"
	"log"
	"net/http"
	"os"
	"strconv"

	"github.com/gin-gonic/gin"
	"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	yaml "sigs.k8s.io/yaml/goyaml.v3"
)

type OrderHandler struct {
	OrderService *service.OrderService
	AuthClient   *AuthClient
}

type AuthClient struct {
	client authpb.AuthServiceClient
	conn   *grpc.ClientConn
}

type Config struct {
	AuthService auth_service `yaml:"auth_service"`
}

type auth_service struct {
	Addr string `yaml:"addr"`
}

func NewAuthClient(configPath string) (*AuthClient, error) {
	var config Config
	yamlFile, err := os.ReadFile(configPath)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal(yamlFile, &config)
	if err != nil {
		return nil, err
	}
	conn, err := grpc.NewClient(
		config.AuthService.Addr,
		grpc.WithTransportCredentials(insecure.NewCredentials()),
		//添加otel遥测
		grpc.WithStatsHandler(otelgrpc.NewClientHandler()),
	)
	if err != nil {
		return nil, err
	}
	return &AuthClient{
		client: authpb.NewAuthServiceClient(conn),
		conn:   conn,
	}, nil
}

func (c *AuthClient) Close() error {
	return c.conn.Close()
}

func NewOrderHandler(configPath string) (*OrderHandler, error) {
	orderService := service.NewOrderService(configPath)
	authClient, err := NewAuthClient(configPath)
	if err != nil {
		return nil, err
	}
	return &OrderHandler{
		OrderService: orderService,
		AuthClient:   authClient,
	}, nil
}

func (h *OrderHandler) CreateOrder(c *gin.Context) {
	order := &orderpb.Order{}
	c.ShouldBindJSON(&order)
	userID, ok := c.Get("user_id")
	if !ok {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "user_id is required"})
		return
	}
	log.Println("userID", userID)
	userIDStr := userID.(string)
	log.Println("userIDStr", userIDStr)
	//将userIDStr转换为int32
	userIDInt, err := strconv.ParseInt(userIDStr, 10, 32)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	order.UserId = int32(userIDInt)
	log.Println("order", order)
	orderID, err := h.OrderService.CreateOrder(order)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"order_id": orderID})
}

func (h *OrderHandler) GetOrder(c *gin.Context) {
	orderID := c.Param("order_id")
	log.Println("orderID", orderID)
	orderIDInt, err := strconv.ParseInt(orderID, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid order ID"})
		return
	}
	order, err := h.OrderService.GetOrder(orderIDInt)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, order)
}

func (h *OrderHandler) CancelOrder(c *gin.Context) {
	orderID := c.Param("id")
	log.Println("orderID", orderID)
	orderIDInt, err := strconv.ParseInt(orderID, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid order ID" + err.Error()})
		return
	}
	err = h.OrderService.CancelOrder(orderIDInt)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"success": true})
}

func (h *OrderHandler) MarkOrderPaid(c *gin.Context) {
	orderID := c.Param("id")
	log.Println("order	ID", orderID)
	orderIDInt, err := strconv.ParseInt(orderID, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid order ID"})
		return
	}
	success := c.PostForm("success")
	successBool, err := strconv.ParseBool(success)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid success value"})
		return
	}
	err = h.OrderService.MarkOrderPaid(orderIDInt, successBool)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"success": true})
}

func (h *OrderHandler) Middleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		//服务端添加了otelgin.Middleware("order-service")，所以不需要创建子span
		// //从请求上下文
		// ctx := c.Request.Context()

		// //创建子span
		// ctx, orderSpan := otel.Tracer("auth-gin-middleware").Start(
		// 	ctx,
		// 	"auth-gin-middleware",
		// )
		// defer orderSpan.End()
		// //将上下文设置回请求
		// c.Request = c.Request.WithContext(ctx)
		token := c.GetHeader("Authorization")
		if token == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Missing authorization token"})
			c.Abort()
			return
		}
		response, err := h.AuthClient.client.ValidateToken(c.Request.Context(), &authpb.ValidateTokenRequest{
			Token: token,
		})
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
			c.Abort()
			return
		}
		if response.Valid {
			c.Set("user_id", response.UserId)
			c.Set("role", response.Role)
			c.Next()
		} else {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
			c.Abort()
			return
		}
	}
}
